import base64
import binascii
import uuid

from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from django.db import transaction
from rest_framework import serializers
from .models import TemplateCategory, TemplateElement, Template, TemplateLayerGroup, TemplateLayerGroupElement
from ..AssetsManagement.models import Asset


class Base64FileField(serializers.CharField):
    """通用Base64文件处理字段"""

    def __init__(self,
                 allowed_types: list,
                 max_size: int,
                 storage_path: str,
                 file_prefix: str,
                 **kwargs):
        super().__init__(**kwargs)
        self.allowed_types = allowed_types
        self.max_size = max_size
        self.storage_path = storage_path
        self.file_prefix = file_prefix

    def to_internal_value(self, data):
        try:
            if ';base64,' not in data:
                raise serializers.ValidationError("无效的Base64格式")

            # 解析数据
            header, data = data.split(';base64,', 1)
            mime_type = header.split('/')[-1].lower()

            # 验证类型
            if mime_type not in self.allowed_types:
                raise serializers.ValidationError(f"仅支持 {','.join(self.allowed_types)} 格式")

            # 解码文件
            decoded_file = base64.b64decode(data)

            # 验证大小
            if len(decoded_file) > self.max_size:
                raise serializers.ValidationError(f"文件大小超过 {self.max_size // 1024 // 1024}MB 限制")

            # 生成存储路径
            file_name = f"{self.file_prefix}{uuid.uuid4()}.{mime_type}"
            full_path = f"{self.storage_path}/{file_name}"

            # 保存文件
            default_storage.save(
                full_path,
                ContentFile(decoded_file)
            )
            return full_path

        except (TypeError, ValueError, binascii.Error) as e:
            raise serializers.ValidationError("无效的Base64数据")


class TemplateImageField(Base64FileField):
    """模板图片专用字段"""

    def __init__(self, **kwargs):
        super().__init__(
            allowed_types=['png', 'jpeg', 'jpg', 'gif'],
            max_size=5 * 1024 * 1024,  # 5MB
            storage_path="templates",
            file_prefix="template_",
            **kwargs
        )


class CategoryIconField(Base64FileField):
    """分类图标专用字段"""

    def __init__(self, **kwargs):
        super().__init__(
            allowed_types=['png', 'svg', 'jpeg', 'jpg'],
            max_size=2 * 1024 * 1024,  # 2MB
            storage_path="icons/category",
            file_prefix="category_",
            **kwargs
        )


#################分类序列化器#################
class TemplateCategorySerializer(serializers.ModelSerializer):
    icon_base64 = CategoryIconField(write_only=True, required=False)
    parent = serializers.PrimaryKeyRelatedField(
        queryset=TemplateCategory.objects.all(),
        required=False,
        allow_null=True
    )

    class Meta:
        model = TemplateCategory
        fields = [
            'id', 'name', 'description', 'parent',
            'icon_url', 'position', 'created_at',
            'updated_at', 'icon_base64'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at', 'icon_url', 'position']
        extra_kwargs = {
            'name': {'min_length': 2, 'max_length': 100},
            'position': {'min_value': 0}
        }

    def validate_parent(self, value):
        """验证父分类合法性"""
        if self.instance and value:
            # 防止循环依赖
            if value == self.instance:
                raise serializers.ValidationError("不能设置自己为父分类")
            if value.parent and value.parent == self.instance:
                raise serializers.ValidationError("不能形成分类循环")
        return value

    def create(self, validated_data):
        icon_base64 = validated_data.pop('icon_base64', None)
        if icon_base64:
            validated_data['icon_url'] = icon_base64
        return super().create(validated_data)

    def update(self, instance, validated_data):
        icon_base64 = validated_data.pop('icon_base64', None)
        if icon_base64:
            # 删除旧图标
            if instance.icon_url:
                default_storage.delete(instance.icon_url)
            validated_data['icon_url'] = icon_base64
        return super().update(instance, validated_data)


class DetailTemplateCategorySerializer(TemplateCategorySerializer):
    children = serializers.SerializerMethodField()

    class Meta(TemplateCategorySerializer.Meta):
        fields = TemplateCategorySerializer.Meta.fields + ['children']

    def get_children(self, obj):
        return DetailTemplateCategorySerializer(obj.children.all(), many=True).data


#################模板序列化器#################
class TemplateElementSerializer(serializers.ModelSerializer):
    asset = serializers.PrimaryKeyRelatedField(
        queryset=Asset.objects.all(),
        required=False,
        allow_null=True,
        help_text="关联资源ID（当元素类型为mask时必填）"
    )

    class Meta:
        model = TemplateElement
        fields = [
            'id', 'origin_element_id', 'template', 'type', 'content', 'position', 'z_index', 'asset', 'frame_style',
            'name', 'size', 'rotation', 'opacity', 'visible', 'locked', 'group_parent_id'
        ]
        extra_kwargs = {
            'id': {'required': False},
            'template': {'required': False},
        }

    def validate(self, data):
        # 类型与资源的关联校验
        element_type = data.get('type')
        asset = data.get('asset')

        if element_type == "mask":
            if not asset:
                raise serializers.ValidationError({"asset": "蒙版元素必须关联资源"})
            if asset.type != "mask":
                raise serializers.ValidationError({"asset": "资源类型必须为蒙版"})
        else:
            if asset is not None:
                raise serializers.ValidationError({"asset": "非蒙版元素不可关联资源"})

        return data


class TemplateLayerGroupSerializer(serializers.ModelSerializer):
    element = serializers.SerializerMethodField(help_text="元素ID")
    children = serializers.SerializerMethodField(help_text="子图层组列表")

    class Meta:
        model = TemplateLayerGroup
        fields = ['id', 'template', 'name', 'visible', 'locked', 'z_index', 'parent', 'element', 'children']
        extra_kwargs = {
            'parent': {'required': False, 'allow_null': True}
        }

    def get_element(self, obj):
        group_element = obj.element_group_mapping.first()
        return group_element.element.origin_element_id if group_element else None

    def get_children(self, obj):
        children = obj.children.all().order_by('z_index')
        return TemplateLayerGroupSerializer(children, many=True).data


class WritableTemplateLayerGroupSerializer(serializers.ModelSerializer):
    element = serializers.CharField(help_text="元素origin_element_id", required=False)
    children = serializers.ListField(child=serializers.DictField(), required=False, default=list)

    class Meta:
        model = TemplateLayerGroup
        fields = ['id', 'name', 'visible', 'locked', 'z_index', 'parent', 'element', 'children']
        extra_kwargs = {
            'id': {'required': False},
            'parent': {'required': False, 'allow_null': True}
        }

    def to_internal_value(self, data):
        # 保留children数据，但不作为模型字段
        self._children = data.get('children', [])
        return super().to_internal_value(data)

    def to_representation(self, instance):
        # 用于输入验证后的数据展示
        data = super().to_representation(instance)
        data['children'] = self._children if hasattr(self, '_children') else []
        return data


class TemplateSerializer(serializers.ModelSerializer):
    elements = TemplateElementSerializer(many=True)
    layer_groups = WritableTemplateLayerGroupSerializer(many=True, required=False)
    thumbnail_base64 = TemplateImageField(write_only=True, required=False)
    preview_base64 = TemplateImageField(write_only=True, required=False)

    class Meta:
        model = Template
        fields = [
            'id', 'category', 'name', 'description', 'thumbnail_url',
            'canvas_size', 'background', 'preview_url', 'internal_notes', 'elements',
            'thumbnail_base64', 'preview_base64', 'layer_groups', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
        extra_kwargs = {
            'thumbnail_url': {'read_only': True},
            'preview_url': {'read_only': True}
        }

    def create(self, validated_data):
        elements_data = validated_data.pop('elements')
        layer_groups_data = validated_data.pop('layer_groups', [])
        thumbnail = validated_data.pop('thumbnail_base64', None)
        preview = validated_data.pop('preview_base64', None)

        with transaction.atomic():
            template = Template.objects.create(thumbnail_url=thumbnail, preview_url=preview, **validated_data)

            for element_data in elements_data:
                asset = element_data.pop('asset', None)
                TemplateElement.objects.create(template=template, asset=asset, **element_data)

            # 递归创建图层组及其关联
            def create_layer_groups(groups_data, parent=None, top_group=None):
                for group_data in groups_data:
                    origin_element_id = group_data.pop('element', None)
                    children_data = group_data.pop('children', [])

                    # 创建组
                    group = TemplateLayerGroup.objects.create(template=template, parent=parent, **group_data)

                    # 如果是顶层组且有子元素，记录为 top_group
                    if parent is None and children_data:
                        top_group = group

                    if origin_element_id is not None:
                        # 获取元素
                        element = TemplateElement.objects.get(origin_element_id=origin_element_id, template=template)

                        # 创建组和元素的关联
                        TemplateLayerGroupElement.objects.create(group=group, element=element)

                        # 如果存在 top_group，设置元素的 group_parent_id
                        if top_group and parent is not None:
                            element.group_parent_id = top_group.id
                            element.save()

                    # 递归处理子组，传递 top_group
                    create_layer_groups(children_data, parent=group, top_group=top_group)

            create_layer_groups(layer_groups_data)
            return template

    def update(self, instance, validated_data):
        elements_data = validated_data.pop('elements')
        layer_groups_data = validated_data.pop('layer_groups', [])
        thumbnail = validated_data.pop('thumbnail_base64', None)
        preview = validated_data.pop('preview_base64', None)

        with transaction.atomic():
            # 处理文件更新
            if thumbnail:
                if instance.thumbnail_url:
                    default_storage.delete(instance.thumbnail_url)
                instance.thumbnail_url = thumbnail
            if preview:
                if instance.preview_url:
                    default_storage.delete(instance.preview_url)
                instance.preview_url = preview

            # 更新模板字段
            for attr, value in validated_data.items():
                setattr(instance, attr, value)
            instance.save()

            # 处理元素更新
            existing_ids = [e['id'] for e in elements_data if 'id' in e]
            # 删���不存在于请求中的元素
            instance.elements.exclude(id__in=existing_ids).delete()

            for element_data in elements_data:
                element_id = element_data.get('id', None)
                asset = element_data.pop('asset', None)

                if element_id:
                    element = TemplateElement.objects.get(id=element_id)
                    element.asset = asset  # 更新资源关联
                    for attr, value in element_data.items():
                        setattr(element, attr, value)
                    element.save()
                else:
                    TemplateElement.objects.create(
                        template=instance,
                        asset=asset,
                        **element_data
                    )

            # 处理图层组更新
            existing_group_ids = []

            def update_layer_groups(groups_data, parent=None, top_group=None):
                for group_data in groups_data:
                    group_id = group_data.get('id')
                    origin_element_id = group_data.pop('element', None)
                    children_data = group_data.pop('children', [])

                    # 如果是顶层组且有子元素,记录为top_group
                    if parent is None and children_data:
                        new_top_group = True
                    else:
                        new_top_group = False

                    if group_id:
                        group = TemplateLayerGroup.objects.get(id=group_id, template=instance)
                        existing_group_ids.append(group_id)
                        # 更新字段
                        group.name = group_data.get('name', group.name)
                        group.visible = group_data.get('visible', group.visible)
                        group.locked = group_data.get('locked', group.locked)
                        group.z_index = group_data.get('z_index', group.z_index)
                        group.parent = parent
                        group.save()
                    else:
                        group = TemplateLayerGroup.objects.create(template=instance, parent=parent,
                                                                  **group_data)
                        if origin_element_id is not None:
                            # 关联元素
                            element = TemplateElement.objects.get(origin_element_id=origin_element_id, template=instance)
                            TemplateLayerGroupElement.objects.create(group=group, element=element)

                        existing_group_ids.append(group.id)

                    # 设置当前组为新的top_group
                    if new_top_group:
                        top_group = group

                    # 如果存在top_group且不是顶层,更新元素的group_parent_id
                    if top_group and parent is not None and origin_element_id is not None:
                        element = TemplateElement.objects.get(origin_element_id=origin_element_id, template=instance)
                        element.group_parent_id = top_group.id
                        element.save()

                    # 递归处理子组,传递top_group
                    update_layer_groups(children_data, parent=group, top_group=top_group)

            update_layer_groups(layer_groups_data)
            # 删除未包含的旧组
            instance.template_layer_groups.exclude(id__in=existing_group_ids).delete()
            return instance
